namespace PayPal.Platform.SDK
{
    using System;
    using System.IO;
    using System.Text;
    using System.Xml.Serialization;

    /// <summary>
    /// Summary description for SoapEncoder.
    /// </summary>
    public class SoapEncoder
    {
        public SoapEncoder()
        {
            // TODO: Add constructor logic here
        }
        
        /// <summary>
        /// Encodes/converts the given object into SOAP Envelope format
        /// </summary>
        /// <param name="obj">object needs to be encoded</param>
        /// <returns>SOAP Encoded string</returns>
        public static string Encode(object obj)
        {
            string soapRequest, xml = string.Empty;
            StringWriter output = null;
            XmlSerializer serializer = null;

            try
            {
                /// Initializing the XMLSerializer.
                using (output = new StringWriter(new StringBuilder()))
                {
                    serializer = new XmlSerializer(obj.GetType());

                    /// Serializing object into XML.
                    serializer.Serialize(output, obj);

                    /// Constructing the SOAP Outer Envelope format.
                    soapRequest = @"<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/""><soap:Body>";

                    /// Adding SOAP Envelope to Serialized XML string.
                    xml = output.ToString().Replace("xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"", string.Empty);
                    xml = xml.Replace("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", string.Empty);
                    xml = xml.Replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>", string.Empty).Trim();
                    xml = xml.Replace("\r\n", string.Empty);
                    xml = xml.Replace(" ", string.Empty);
                    soapRequest = soapRequest + xml.Trim();
                    soapRequest = soapRequest + @"</soap:Body></soap:Envelope>";

                    return soapRequest;
                }
            }
            catch (FATALException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new FATALException("Error occurred in SoapEncoder->Encode method", ex);
            }
            finally
            {
                output = null;
                serializer = null;
            }
        }

        /// <summary>
        /// Decodes/converts the given SOAP Envelope to given object
        /// </summary>
        /// <param name="soapEnvelope">SOAP envelope needs to be Decoced</param>
        /// <param name="toType">type of object to be converted/decoded from given SAOP Envelope</param>
        /// <returns>Given type Object</returns>
        public static object Decode(string soapEnvelope, Type toType)
        {
            XmlSerializer serializer = null;

            try
            {
                /// Initializing the XMLSerializer.
                serializer = new XmlSerializer(toType);

                /// Removing SOAP outer Envelope
                soapEnvelope = soapEnvelope.Replace("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"><soapenv:Header /><soapenv:Body>", string.Empty);
                soapEnvelope = soapEnvelope.Replace("</soapenv:Body></soapenv:Envelope>", string.Empty);
                soapEnvelope = soapEnvelope.Replace("xmlns:ns2=\"http://svcs.paypal.com/types/ap\"", string.Empty);
                soapEnvelope = soapEnvelope.Replace("ns2:", string.Empty);
                soapEnvelope = soapEnvelope.Replace("soapenv:", string.Empty);
                soapEnvelope = soapEnvelope.Replace("ns3:", string.Empty);
                soapEnvelope = soapEnvelope.Replace("xmlns:ns2=\"http://svcs.paypal.com/types/ap\"", string.Empty);

                /// Deserializing and Returning the XML
                using (MemoryStream reader = new MemoryStream(Encoding.UTF8.GetBytes(soapEnvelope)))
                {
                    return (object)serializer.Deserialize(reader);
                }                
            }
            catch (FATALException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new FATALException("Error occurred in SoapEncoder->Decode method", ex);
            }
            finally
            {
                serializer = null;
            }
        }
    }
}
